﻿using System;
using NUnit.Framework;
using Rhino.Mocks;
using ShuttleBus;
using ShuttleBus.AdminMessages;
using ShuttleBus.Serialization;
using ShuttleBus.Transports.AmazonSqs;
using Tests.Transports.AmazonSqs.Fakes;

namespace Tests.Transports.AmazonSqs.TransportTests
{
    public partial class TransportTests
    {
        [TestFixture]
        public class WhenSendingAMessage
        {
            private SqsTransport _transport;

            private IEndpoint _endpoint;
            private IQueue _queue;
            private ICreateStreams _streamFactory;
            private IReadStreams _streamReader;
            private ISerializer _serializer;

            [SetUp]
            public void SetUp()
            {
                _endpoint = MockRepository.GenerateMock<IEndpoint>();
                _streamFactory = MockRepository.GenerateMock<ICreateStreams>();
                _streamReader = MockRepository.GenerateMock<IReadStreams>();
                _serializer = MockRepository.GenerateMock<ISerializer>();

                _transport = new SqsTransport(_endpoint, _serializer,0, _streamFactory, _streamReader, 5);

                _queue = MockRepository.GenerateMock<IQueue>();

            }

            [TearDown]
            public void TearDown()
            {
                _endpoint.VerifyAllExpectations();
                _streamReader.VerifyAllExpectations();
                _streamFactory.VerifyAllExpectations();
                _queue.VerifyAllExpectations();
                _serializer.VerifyAllExpectations();
            }

            [Test]
            public void DoesNothingWhenMessageIsNull()
            {
                _transport.Send(null, new Subscription(new Uri("sqs://somewhere"), typeof(object)));
            }

            [Test]
            public void DoesNothingWhenSubsriptionIsNull()
            {
                _transport.Send(new TransportMessage(), null);
            }

            [Test]
            public void PutsMessageOnQueue()
            {
                var message = new TransportMessage();
                var location = new Uri("sqs://somewhere/");
                var subscription = new Subscription(location, typeof(MyMessage));
                var serializedMessage = "serialized message";

                var stream = MockRepository.GenerateStub<IStream>();

                _endpoint.Expect(e => e.Initialize(QueueMode.Send)).Return(_queue);

                _streamFactory.Expect(s => s.Create()).Return(stream);
                _serializer.Expect(s => s.Serialize(Arg<IStream>.Is.Same(stream), Arg<TransportMessage>.Is.Same(message)));
                _streamReader.Expect(s => s.ReadAll(stream)).Return(serializedMessage);
                _queue.Expect(q => q.Send(serializedMessage, location));

                _transport.Send(message, subscription);
            }

            [Test]
            [ExpectedException(typeof(DataMisalignedException))]
            public void ExceptionOccursWhenSendingAMessage()
            {
                var message = new TransportMessage();
                var location = new Uri("sqs://somewhere/");
                var subscription = new Subscription(location, typeof(MyMessage));

                var stream = MockRepository.GenerateStub<IStream>();

                _endpoint.Expect(e => e.Initialize(QueueMode.Send)).Return(_queue);

                _streamFactory.Expect(s => s.Create()).Return(stream);
                _serializer.Expect(s => s.Serialize(Arg<IStream>.Is.Same(stream), Arg<TransportMessage>.Is.Same(message)));
                _streamReader.Expect(s => s.ReadAll(stream)).Throw(new DataMisalignedException());

                _transport.Send(message, subscription);
            }
        }
    }
}